package com.jn.service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.ibatis.annotations.Param;

import com.jn.ann.Entity;
import com.jn.ann.EntityRelevance;
import com.jn.ann.EntitysRelevance;
import com.jn.dao.BaseMapper;
import com.jn.entity.BaseEntity;
import com.jn.entity.EntityLimit;
import com.jn.entity.EntityQuery;
import com.jn.entity.EntityScheme;
import com.jn.entity.EntitySort;
import com.jn.tools.IDTools;

public class CrduDao{
	
	private BaseMapper baseMapper;
	
	public CrduDao(BaseMapper baseMapper) {
		this.baseMapper = baseMapper;
	}
	
	public <T extends BaseEntity> Integer insertOrUpdate(T t) {
		String tableName = t.getClass().getAnnotation(Entity.class).tableName();
		String keyName = t.getClass().getAnnotation(Entity.class).keyName();
        Map<String,Object> param = new HashMap<String,Object>();
        List<String> cols = new ArrayList<String>();
		List<Object> vals = new ArrayList<Object>();
		param.put("tableName", tableName);
		param.put("cols", cols);
		param.put("vals", vals);
		if(t.getV(keyName) == null || t.getV(keyName).toString().trim().equals("")){
		    t.setKV(keyName, IDTools.ID());
			return this.insert(t);
		}else {
			return this.update(t);
		}

	}

	public <T extends BaseEntity> Integer insert(T t) {
		String tableName = t.getClass().getAnnotation(Entity.class).tableName();
		String keyName = t.getClass().getAnnotation(Entity.class).keyName();
		
		Set<String> names = baseMapper.selectColNames(tableName);
		
//		if(t.getV(keyName) == null || t.getV(keyName).toString().trim().equals("")){
//			try {
//				throw new Exception("对象主键为空");
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//			return 0;
//		}
//		
		List<String> cols = new ArrayList<String>();
		List<Object> vals = new ArrayList<Object>();
		
		Integer number = 0;
		
		for(String key : t.keySet()){
			if(names.contains(key)){
				cols.add(number, key);
				vals.add(number, t.get(key));
				number++;
			}else{
				System.err.println("警告 : " + key +" 与表字段不符");
			} 
		}
		
		Map<String,Object> param = new HashMap<String,Object>();
		
		param.put("tableName", tableName);
		param.put("cols", cols);
		param.put("vals", vals);
		
		return baseMapper.insert(param);
	}
	
	public <T extends BaseEntity> Integer update(T t) {
		String keyName = t.getClass().getAnnotation(Entity.class).keyName();
		if(t.getV(keyName) == null || t.getV(keyName).toString().trim().equals("")){
			try {
				throw new Exception("对象主键不能为空");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return updateByQuery(t, new EntityQuery(keyName,"=",t.getV(keyName)));
	}

	public <T extends BaseEntity> Integer updateByQuery(T t, EntityQuery... querys) {
		String tableName = t.getClass().getAnnotation(Entity.class).tableName();
		String keyName = t.getClass().getAnnotation(Entity.class).keyName();
		Map<String,Object> param = new HashMap<String,Object>();
		
		Set<String> names = baseMapper.selectColNames(tableName);
		List<EntityQuery> queryList = new ArrayList<EntityQuery>();
		for(EntityQuery query : querys){
			if(names.contains(query.getColName())){
				queryList.add(query);
			}else{
				System.err.println("警告 : " + query.getColName() +" 与表字段不符");
			}
		}
		
		t.remove(keyName);
		
		param.put("tableName", tableName);
		param.put("updateVal", t);
		param.put("query", queryList);
		
		return baseMapper.update(param);
	}

	public <T extends BaseEntity> Integer del(T t) {
		String keyName = t.getClass().getAnnotation(Entity.class).keyName();
		
		if(t.getV(keyName) == null || t.getV(keyName).toString().trim().equals("")){
			try {
				throw new Exception("对象主键不能为空");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		return delByQuery(t.getClass(), new EntityQuery(keyName,"=",t.get(keyName)));
	}

	public Integer delByPrivateKey(Class<? extends BaseEntity> clzz, String privateKey) {
		String keyName = clzz.getAnnotation(Entity.class).keyName();
		if(privateKey == null || privateKey.trim().equals("")){
			try {
				throw new Exception("对象主键不能为空");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return delByQuery(clzz, new EntityQuery(keyName,"=",privateKey));
	}

	public Integer delByQuery(Class<? extends BaseEntity> clzz, EntityQuery... querys) {
		String tableName = clzz.getAnnotation(Entity.class).tableName();
		
		List<EntityQuery> queryList = new ArrayList<EntityQuery>();
		Set<String> names = baseMapper.selectColNames(tableName);
		
		for(EntityQuery query : querys){
			if(names.contains(query.getColName())){
				queryList.add(query);
			}else{
				System.err.println("警告 : " + query.getColName() +" 与表字段不符");
			}
		}
		
		Map<String,Object> param = new HashMap<String,Object>();
		param.put("tableName", tableName);
		param.put("query", queryList);
		
		return baseMapper.delete(param);
	}

	public <T extends BaseEntity> T selectByPrivateKey(Class<? extends BaseEntity> clzz, EntityScheme[] entitySchemes, Boolean nest, String privateKey) {
		String keyName = clzz.getAnnotation(Entity.class).keyName();
		if(privateKey == null || privateKey.trim().equals("")){
			try {
				throw new Exception("对象主键不能为空");
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		}
		List<T> tList = selectByQueryLimit(clzz, entitySchemes, nest, null, null, new EntityQuery(keyName,"=",privateKey));
		
		return tList.size()!=0?tList.get(0):null;
	}

	public <T extends BaseEntity> List<T> selectByQuery(Class<? extends BaseEntity> clzz, EntityScheme[] entitySchemes, Boolean nest, EntityQuery... querys) {
		return selectByQueryLimit(clzz, entitySchemes, nest, null, null, querys);
	}

	public <T extends BaseEntity> List<T> selectByQuery(Class<? extends BaseEntity> clzz, EntityScheme[] entitySchemes, Boolean nest, EntitySort entityShort, 
			EntityQuery... querys) {
		return selectByQueryLimit(clzz, entitySchemes, nest, entityShort, null, querys);
	}

	@SuppressWarnings("unchecked")
	public <T extends BaseEntity> List<T> selectByQueryLimit(Class<? extends BaseEntity> clzz, EntityScheme[] entitySchemes, Boolean nest, EntitySort entityShort, 
			EntityLimit entityLimit, EntityQuery... querys) {
		String keyName = clzz.getAnnotation(Entity.class).keyName();
		String tableName = clzz.getAnnotation(Entity.class).tableName();
		Map<String,EntityScheme> schemeMap = new HashMap<String,EntityScheme>();
		
		Map<String,Object> param = new HashMap<String,Object>();
		
		Set<String> names = baseMapper.selectColNames(tableName);
	
		if(entitySchemes != null){
			String colNamesStr = "";
			for(EntityScheme entityScheme : entitySchemes){
				if(names.contains(entityScheme.getColName())){
					if(entityScheme.getTransverter() != null){
						schemeMap.put(entityScheme.getColName(), entityScheme);
					}
					if(!colNamesStr.contains(entityScheme.getColName())){
						colNamesStr += ( entityScheme.getColName() + "," );
					}
				}else{
					System.err.println("警告 : 方案 " + entityScheme.getColName() +" 与表字段不符");
				}
			}
			if(!colNamesStr.trim().equals("")){
				colNamesStr += keyName;
				param.put("colNamesStr", colNamesStr);
			}
		}
		
		if(entityShort != null){
			String shorStr = "";
			String colShortStr = entityShort.getColName();
			if(colShortStr.contains(",")){
				String[] shortStrs = colShortStr.split(","); 
				for(String str : shortStrs){
					if(names.contains(str)){
						shorStr += ( str + "," );
					}else{
						System.err.println("警告 : 排序字段 " + str +" 与表字段不符");
					}
				}
				entityShort.setColName(shorStr.substring(0, shorStr.length()-1));
				if(!entityShort.getColName().trim().equals("")){
					param.put("short", entityShort);
				}
				
			}else{
				if(names.contains(colShortStr.trim())){
					entityShort.setColName(colShortStr);
					param.put("short", entityShort);
				}
			}
		}
		
		param.put("limit", entityLimit);
		
		List<EntityQuery> queryList = new ArrayList<EntityQuery>();
		
		for(EntityQuery query : querys){
			if(names.contains(query.getColName())){
				queryList.add(query);
			}else{
				System.err.println("警告 : " + query.getColName() +" 与表字段不符");
			}
		}
		
		param.put("tableName", tableName);
		param.put("query", queryList);
		
		List<Map<String,Object>> returnObjectMapList = baseMapper.selectByQuery(param);
		
		List<T> returnObject = new ArrayList<T>();
		
		try {
			for(Map<String,Object> map : returnObjectMapList){
				T o = (T) clzz.newInstance();
				if(nest){
					Field[] fields = o.getClass().getDeclaredFields();
					for(Field field : fields){
						if(field.getAnnotation(EntityRelevance.class) != null){
							String fieldStr = field.getAnnotation(EntityRelevance.class).field();
							String targetFieldStr = field.getAnnotation(EntityRelevance.class).targetField();
							Class<? extends BaseEntity> relevanceClass = (Class<? extends BaseEntity>) field.getType();
							
							Object fieldObj = map.get(fieldStr);
							if(fieldObj == null){
								System.err.println("警告 ：" + o.getClass() + " 类型字段 " + fieldStr + " 与 目标类型字段" + relevanceClass + " " + targetFieldStr + " 关联对象值为空，请检查实体方案");
							}
							
//							field.setAccessible(true);
//							field.set(o, selectByQueryLimit(relevanceClass,null,nest,null,null,new EntityQuery(targetFieldStr, "=", fieldObj)).get(0));
							o.setKV(field.getName(), selectByQueryLimit(relevanceClass,null,nest,null,null,new EntityQuery(targetFieldStr, "=", fieldObj)));
						}
						if(field.getAnnotation(EntitysRelevance.class) != null){
							String fieldStr = field.getAnnotation(EntitysRelevance.class).field();
							String targetFieldStr = field.getAnnotation(EntitysRelevance.class).targetField();
							Class<? extends BaseEntity> relevanceClass = field.getAnnotation(EntitysRelevance.class).targetClass();
							
							Object fieldObj = map.get(fieldStr);
							if(fieldObj == null){
								System.err.println("警告 ：" + o.getClass() + " 类型字段" + fieldStr + " 与 目标类型字段" + relevanceClass + " " + targetFieldStr + " 关联对象值为空，请检查实体方案");
							}
//							field.setAccessible(true);
//							field.set(o, selectByQueryLimit(relevanceClass,null,nest,null,null,new EntityQuery(targetFieldStr, "=", fieldObj)));
							o.setKV(field.getName(), selectByQueryLimit(relevanceClass,null,nest,null,null,new EntityQuery(targetFieldStr, "=", fieldObj)));
							
						}
					}
				}
				for(String k : map.keySet()){
					if(schemeMap.get(k) != null){
						o.put(k, schemeMap.get(k).getTransverter().transverter(map.get(k)));
					}else{
						o.put(k, map.get(k));
					}
				}
				returnObject.add(o);
			}
			
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		return returnObject;
	}
	
	public Integer selectCountByQuery(Class<? extends BaseEntity> clzz, EntityQuery... querys) {
		String tableName = clzz.getAnnotation(Entity.class).tableName();
		List<EntityQuery> queryList = new ArrayList<EntityQuery>();
		
		Map<String,Object> param = new HashMap<String,Object>();
		Set<String> names = baseMapper.selectColNames(tableName);
		
		for(EntityQuery query : querys){
			if(names.contains(query.getColName())){
				queryList.add(query);
			}else{
				System.err.println("警告 : " + query.getColName() +" 与表字段不符");
			}
		}
		
		param.put("tableName", tableName);
		param.put("query", queryList);
		
		return baseMapper.selectCountByQuery(param);
	}
	
	public <T extends BaseEntity> List<T> selectEntitySqlInject(Class<? extends BaseEntity> clzz, String sql){
		List<T> returnObject = new ArrayList<T>();
		List<Map<String,Object>> returnMapList =  baseMapper.selectEntitySqlInject(sql);
		try {
			for(Map<String,Object> map : returnMapList){
				T o = (T) clzz.newInstance();
					Field[] fields = o.getClass().getDeclaredFields();
					for(Field field : fields){
						if(field.getAnnotation(EntityRelevance.class) != null){
							String fieldStr = field.getAnnotation(EntityRelevance.class).field();
							String targetFieldStr = field.getAnnotation(EntityRelevance.class).targetField();
							Class<? extends BaseEntity> relevanceClass = (Class<? extends BaseEntity>) field.getType();
							
							Object fieldObj = map.get(fieldStr);
							if(fieldObj == null){
								System.err.println("警告 ：" + o.getClass() + " 类型字段 " + fieldStr + " 与 目标类型字段" + relevanceClass + " " + targetFieldStr + " 关联对象值为空，请检查实体方案");
							}
						}
						if(field.getAnnotation(EntitysRelevance.class) != null){
							String fieldStr = field.getAnnotation(EntitysRelevance.class).field();
							String targetFieldStr = field.getAnnotation(EntitysRelevance.class).targetField();
							Class<? extends BaseEntity> relevanceClass = field.getAnnotation(EntitysRelevance.class).targetClass();
							
							Object fieldObj = map.get(fieldStr);
							if(fieldObj == null){
								System.err.println("警告 ：" + o.getClass() + " 类型字段" + fieldStr + " 与 目标类型字段" + relevanceClass + " " + targetFieldStr + " 关联对象值为空，请检查实体方案");
							}
						}
					}
				for(String k : map.keySet()){
					o.put(k, map.get(k));
				}
				returnObject.add(o);
			}
			
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		return returnObject;
	}
	
	List<Long> selectLongsSqlInject(@Param("sql") String sql){
		return baseMapper.selectLongsSqlInject(sql);
	}
	
	List<Double> selectDoublesSqlInject(String sql){
		return baseMapper.selectDoublesSqlInject(sql);
	}
	
	List<Integer> selectIntsSqlInject(String sql){
		return baseMapper.selectIntsSqlInject(sql);
	}
	
	List<String> selectStrsSqlInject(String sql){
		return baseMapper.selectStrsSqlInject(sql);
	}
	
	List<Map<String,Object>> selectEntitySqlInject(String sql){
		return baseMapper.selectEntitySqlInject(sql);
	}
	
	List<Map<String,Object>> selectMapsSqlInject(String sql){
		return baseMapper.selectEntitySqlInject(sql);
	}
	
	public Integer selectIntSqlInject(String sql) {
		return baseMapper.selectIntSqlInject(sql);
	};
	
	public String selectStrSqlInject(String sql) {
		return baseMapper.selectStrSqlInject(sql);
	};
	
	public Boolean selectBooleanSqlInject(String sql) {
		return baseMapper.selectBooleanSqlInject(sql);
	};
	
	public Date selectDateSqlInject(String sql) {
		return baseMapper.selectDateSqlInject(sql);
	};
	
	public Long selectLongSqlInject(String sql) {
		return baseMapper.selectLongSqlInject(sql);
	};
	
	public Double selectDoubleSqlInject(String sql) {
		return baseMapper.selectDoubleSqlInject(sql);
	};
	
	public Integer updateSqlInject(String sql) {
		return baseMapper.updateSqlInject(sql);
	};
	
	public Integer insetSqlInject(String sql) {
		return baseMapper.insetSqlInject(sql);
	};
	
	public Integer delSqlInject(String sql) {
		return baseMapper.delSqlInject(sql);
	};
	
}
